﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GraphicsFramework.Collection
{

    public class General : List<Drawing.GraphicBase>
    {

        #region Variables

        private Drawing.SizingHandles.SizingHandle sizinghandles;
        private Enum.EnumDrawingCategory type;
        private Support.Selections selections;

        #endregion

        #region Constructors

        public General()
        {
            this.type = Enum.EnumDrawingCategory.COLLECTION;
            sizinghandles = new Drawing.SizingHandles.SizingHandle();
            selections = new Support.Selections();
        }

        public General(Enum.EnumDrawingCategory type)
        {
            this.type = type;
            sizinghandles = new Drawing.SizingHandles.SizingHandle();
            selections = new Support.Selections();
        }

        #endregion

        #region Rendering

        public virtual void OnRender(GraphicsFramework graphics)
        {
            foreach (Drawing.GraphicBase item in this)
            {
                item.OnRender(graphics);
                graphics.BasicRectangle(Property.DefaultProperty.Node, graphics.ToCoord(item.Center), 5, 5);
            }

            foreach (Drawing.GraphicBase item in this)
            {
                item.OnRender(graphics);
                graphics.BasicRectangle(Property.DefaultProperty.Node, graphics.ToCoord(item.Center), 5, 5);
            }

            if (selections.Count != 0)
                graphics.BasicRectangle(Property.DefaultProperty.Node, graphics.ToCoord(selections.Center), 5, 5);
        }

        public void OnRenderNode(GraphicsFramework graphics)
        {
            Entity.Rectangle2F bounds = selections.GetDrawingsBounds();

            if (bounds != null)
            {
                sizinghandles.Initialize(graphics, bounds.Point1.X, bounds.Point1.Y, bounds.Point2.X, bounds.Point2.Y);
                sizinghandles.OnRender(graphics);
            }

            foreach (Drawing.GraphicBase item in this)
            {
                item.OnRenderNode(graphics);
            }
        }

        #endregion

        #region Selection

        public void SelectByPoint(GraphicsFramework graphics, Entity.Point2F point, bool multiselect)
        {
            Drawing.GraphicBase drawing;
            int x;
            int selectenodes;

            //Clear the selection list.
            if (multiselect)
            {
                //Try to select a drawing.
                for (x = Count - 1; x >= 0; x--)
                {
                    drawing = this[x];
                    if (drawing.Selected)
                    {
                        selectenodes = drawing.SelectedNodes.Count;

                        if (drawing.SelectByPoint(graphics, point, multiselect))
                        {
                            if (selectenodes == drawing.SelectedNodes.Count)
                                drawing.Selected = false;
                        }
                        else
                        {
                            drawing.Selected = true;
                        }
                    }
                    else
                    {
                        if (drawing.SelectByPoint(graphics, point, multiselect))
                            break;

                    }
                }
            }
            else
            {
                //Try to select a drawing.
                for (x = Count - 1; x >= 0; x--)
                {
                    drawing = this[x];
                    if (drawing.SelectByPoint(graphics, point, multiselect))
                        break;
                }

                //Deselect all other drawings.
                for (int y = x - 1; y >= 0; y--)
                    this[y].Selected = false;
            }

            UpdateSelection();

        }

        public void SelectByRectangle(GraphicsFramework graphics, Entity.Rectangle2F bounds)
        {
            foreach (Drawing.GraphicBase drawing in this)
                drawing.SelectByRectangle(graphics, bounds);

            UpdateSelection();
        }

        private void DeleteSelection()
        {
            if (this.Count != 0)
            {
                int x = 0;
                do
                {
                    if (this[x].Selected)
                    {
                        this.RemoveAt(x);
                        x--;
                    }
                    x++;
                } while (x < this.Count);
            }

            UpdateSelection();
        }

        public void ClearSelection()
        {
            //Deselect all drawings.
            for (int x = Count - 1; x >= 0; x--)
                this[x].Selected = false;

            UpdateSelection();
        }

        public void UpdateSelection()
        {
            List<Drawing.GraphicBase> selected = new List<Drawing.GraphicBase>();

            foreach (Drawing.GraphicBase drawing in this)
                if (drawing.Selected)
                    selected.Add(drawing);

            selections.UpdateSelection(selected);
        }

        /// <summary>
        /// Check if a given point is touching one of the selected drawings.
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public bool RetestSelectedByPoint(GraphicsFramework graphics, Entity.Point2F point)
        {
            Drawing.GraphicBase drawing;
            int x;

            //Try to select a drawing.
            for (x = Count - 1; x >= 0; x--)
            {
                drawing = this[x];
                if (drawing.Selected)
                    if (drawing.TestSelectByPoint(graphics, point))
                        return true;
            }

            return false;
        }

        /// <summary>
        /// Use to test if a given point is touching a drawing.
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public bool TestSelectByPoint(GraphicsFramework graphics, Entity.Point2F point)
        {
            Drawing.GraphicBase drawing;
            int x;

            //Try to select a drawing.
            for (x = Count - 1; x >= 0; x--)
            {
                drawing = this[x];
                if (drawing.TestSelectByPoint(graphics, point))
                    return true;
            }

            return false;
        }

        public void SelectAllDrawing()
        {
            foreach (Drawing.GraphicBase drawing in this)
                drawing.Selected = true;

            UpdateSelection();
        }

        public bool DeleteSelectedNode()
        {
            if (this.Count != 0)
            {
                int x = 0;
                do
                {
                    if (this[x].Selected)
                    {
                        if (this[x].SelectedNodes.Count != 0)
                        {
                            this[x].DeleteSelectedNode();
                            return true;
                        }
                    }
                    x++;
                } while (x < this.Count);
            }

            return false;
        }

        public List<Drawing.GraphicBase> SelectedDrawings
        {
            get { return selections.SelectedDrawing; }
        }

        public int SelectedCount
        {
            get { return selections.Count; }
        }

        #endregion

        #region Transformation

        public void Move(Entity.Point2F move, Entity.Point2F snapvalue)
        {
            selections.Move(move, snapvalue);
        }

        public void FlipHorizontal()
        {
            selections.FlipHorizontal();
        }

        public void FlipVertical()
        {
            selections.FlipVertical();
        }

        public void Rotate(float angle, int precision)
        {
            selections.Rotate(angle, precision);
        }

        public void RotateLeft(int precision)
        {
            selections.RotateLeft(precision);
        }

        public void RotateRight(int precision)
        {
            selections.RotateRight(precision);
        }

        public void LeftAlign()
        {
            selections.LeftAlign();
        }

        public void RightAlign()
        {
            selections.RightAlign();
        }

        public void TopAlign()
        {
            selections.TopAlign();
        }

        public void BottomAlign()
        {
            selections.BottomAlign();
        }

        public void HorizontalCenterAlign()
        {
            selections.HorizontalCenterAlign();
        }

        public void VerticalCenterAlign()
        {
            selections.VerticalCenterAlign();
        }

        #endregion

        #region Supporting Functions

        public void Delete()
        {
            if (!DeleteSelectedNode())
                DeleteSelection();
        }

        public Entity.Rectangle2F Bounds()
        {
            if (Count != 0)
            {
                Entity.Rectangle2F bounds = null;
                Entity.Rectangle2F other = null;

                foreach (Drawing.GraphicBase drawing in this)
                {
                    //Check if bounds is still null
                    if (bounds != null)
                    {
                        other = drawing.GetBounds();

                        //Check if drawing bound is null.
                        //Merge to the existing bounds if not null.
                        if (other != null)
                            bounds.Merge(other);
                    }
                    else
                    {
                        bounds = drawing.GetBounds();
                    }
                }

                return bounds;
            }

            return null;
        }

        public void AddNode(GraphicsFramework graphics, Entity.Point2F point)
        {
            Drawing.GraphicBase drawing;

            for (int x = Count - 1; x >= 0; x--)
            {
                drawing = this[x];
                if (drawing.Selected)
                    if (drawing.AddNode(graphics, point))
                        break;
            }
        }

        #endregion

        #region Properties

        public Enum.EnumDrawingCategory Type
        {
            get { return type; }
        }

        #endregion

    }
}

